package com.harmontronics.app.pedestal.bridge;

import android.content.Intent;
import android.text.TextUtils;
import android.webkit.JavascriptInterface;

import com.blankj.utilcode.util.ActivityUtils;
import com.blankj.utilcode.util.EncodeUtils;
import com.blankj.utilcode.util.EncryptUtils;
import com.blankj.utilcode.util.FileIOUtils;
import com.blankj.utilcode.util.FileUtils;
import com.blankj.utilcode.util.GsonUtils;
import com.blankj.utilcode.util.LogUtils;
import com.blankj.utilcode.util.ThreadUtils;
import com.blankj.utilcode.util.Utils;
import com.blankj.utilcode.util.ZipUtils;
import com.harmontronics.app.pedestal.AppConstants;
import com.harmontronics.app.pedestal.agent.WebActivity;
import com.harmontronics.app.pedestal.bridge.model.BaseBridge;
import com.harmontronics.app.pedestal.bridge.model.BridgeCallback;
import com.harmontronics.app.pedestal.bridge.model.BridgeResult;
import com.lzy.okgo.OkGo;
import com.lzy.okgo.cache.CacheMode;
import com.lzy.okgo.callback.FileCallback;
import com.lzy.okgo.callback.StringCallback;
import com.lzy.okgo.exception.OkGoException;
import com.lzy.okgo.model.HttpHeaders;
import com.lzy.okgo.model.Progress;
import com.lzy.okgo.model.Response;
import com.lzy.okgo.request.GetRequest;
import com.lzy.okgo.request.base.Request;
import com.lzy.okserver.OkDownload;
import com.lzy.okserver.download.DownloadListener;
import com.xiasuhuei321.loadingdialog.view.LoadingDialog;
import com.xuexiang.xupdate.utils.Md5Utils;

import org.jetbrains.annotations.NotNull;
import org.json.JSONArray;
import org.json.JSONObject;

import java.io.File;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URL;
import java.net.URLConnection;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import io.reactivex.Observable;
import io.reactivex.ObservableEmitter;
import io.reactivex.ObservableOnSubscribe;
import io.reactivex.ObservableSource;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.Disposable;
import io.reactivex.functions.Consumer;
import io.reactivex.functions.Function;
import io.reactivex.schedulers.Schedulers;
import wendu.dsbridge.CompletionHandler;

public class FileBridge extends BaseBridge {
    private LoadingDialog mLoadingDialog;
    private WebActivity activity;

    public FileBridge(WebActivity activity) {
        this.activity = activity;
    }

    @JavascriptInterface
    public void choose(Object argsJson, CompletionHandler<String> handler) {
        LogUtils.d("FILE.choose");
        if (null == argsJson) {
            handler.complete(fail("参数不能为空", null));
            return;
        }

        try {
            JSONObject args = (JSONObject) argsJson;
            LogUtils.d("args: " + args.toString());
//            count: 6, //默认9
//            extension: ["pdf,doc"],
            String[] patterns = null;
            if (args.has("extension")) {
                JSONArray extension = args.getJSONArray("extension");
                if (extension.length() > 0) {
                    patterns = new String[extension.length()];
                    for (int i = 0; i < extension.length(); i++) {
                        patterns[i] = extension.getString(i).toUpperCase();
                    }
                }
            }

            this.activity.fileChoose(args.has("count") ? args.getInt("count") : 1, patterns, new BridgeCallback() {
                @Override
                public void onSuccess(Object result) {
                    handler.complete(success(result));
                }

                @Override
                public void onFail(String message) {
                    handler.complete(fail(message, null));
                }
            });
        } catch (Exception e) {
            handler.complete(fail(e.getMessage(), e));
        }
    }


    @JavascriptInterface
    public void upload(Object argsJson, CompletionHandler<String> handler) {
        LogUtils.d("FILE.upload");
        if (null == argsJson) {
            handler.complete(fail("参数不能为空", null));
            return;
        }

        try {
            JSONObject args = (JSONObject) argsJson;
            LogUtils.d("args: " + args.toString());
            if (!args.has("uploadUrl")) {
                throw new IllegalArgumentException("uploadUrl不能为空");
            }
            String uploadUrl = args.optString("uploadUrl");
            if (TextUtils.isEmpty(uploadUrl)) {
                throw new IllegalArgumentException("uploadUrl不能为空");
            }

            if (!args.has("headers")) {
                throw new IllegalArgumentException("headers不能为空");
            }
            JSONObject headers = args.optJSONObject("headers");
            if (null == headers) {
                throw new IllegalArgumentException("headers不能为空");
            }

            HttpHeaders httpHeaders = new HttpHeaders();
            Iterator<String> keys = headers.keys();
            while (keys.hasNext()) {
                String key = keys.next();
                String value = headers.optString(key);
                httpHeaders.put(key, value);
            }

            if (!args.has("path")) {
                throw new IllegalArgumentException("上传路径不能为空");
            }
            String path = args.optString("path");
            if (TextUtils.isEmpty(path)) {
                throw new IllegalArgumentException("上传路径不能为空");
            }
            File file = new File(path);
            if (!file.exists()) {
                throw new IllegalArgumentException("上传文件不存在");
            }

            ThreadUtils.runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    if (null == mLoadingDialog) {
                        mLoadingDialog = new LoadingDialog(ActivityUtils.getTopActivity());
                    }
                }
            });

            OkGo.<String>post(uploadUrl)
                    .headers(httpHeaders)
                    .isMultipart(true)
                    .params("file", file)
                    .execute(new StringCallback() {

                        @Override
                        public String convertResponse(okhttp3.Response response) throws Throwable {
                            if (!response.isSuccessful()) {
                                throw new OkGoException("服务器异常[code:" + response.code() + "]");
                            }
                            return super.convertResponse(response);
                        }

                        @Override
                        public void onSuccess(Response<String> response) {
                            ThreadUtils.runOnUiThread(new Runnable() {
                                @Override
                                public void run() {
                                    mLoadingDialog.loadSuccess();
                                }
                            });
                            if (null != response.body() && !TextUtils.isEmpty(response.body())) {
                                BridgeResult result = GsonUtils.fromJson(response.body(), BridgeResult.class);
                                handler.complete(success(result.data));
                            } else {
                                handler.complete(fail("data返回为空", response.getException()));
                            }
                        }

                        @Override
                        public void onStart(Request<String, ? extends Request> request) {
                            super.onStart(request);
                            ThreadUtils.runOnUiThread(new Runnable() {
                                @Override
                                public void run() {
                                    mLoadingDialog.setLoadingText("上传中")
                                            .setSuccessText("上传成功")
                                            .setFailedText("上传失败")
                                            .closeFailedAnim()
                                            .closeSuccessAnim()
                                            .show();
                                }
                            });
                        }

                        @Override
                        public void onError(Response<String> response) {
                            super.onError(response);
                            ThreadUtils.runOnUiThread(new Runnable() {
                                @Override
                                public void run() {
                                    mLoadingDialog.loadFailed();
                                }
                            });
                            handler.complete(fail(response.getException().getMessage(), response.getException()));
                        }
                    });
        } catch (Exception e) {
            handler.complete(fail(e.getMessage(), e));
        }
    }

    @JavascriptInterface
    public void multiUpload(Object argsJson, CompletionHandler<String> handler) {
        LogUtils.d("FILE.multiUpload");
        if (null == argsJson) {
            handler.complete(fail("参数不能为空", null));
            return;
        }

        try {
            JSONObject args = (JSONObject) argsJson;
            LogUtils.d("args: " + args.toString());
            if (!args.has("uploadUrl")) {
                throw new IllegalArgumentException("uploadUrl不能为空");
            }
            String uploadUrl = args.optString("uploadUrl");
            if (TextUtils.isEmpty(uploadUrl)) {
                throw new IllegalArgumentException("uploadUrl不能为空");
            }

            if (!args.has("headers")) {
                throw new IllegalArgumentException("headers不能为空");
            }
            JSONObject headers = args.optJSONObject("headers");
            if (null == headers) {
                throw new IllegalArgumentException("headers不能为空");
            }

            HttpHeaders httpHeaders = new HttpHeaders();
            Iterator<String> keys = headers.keys();
            while (keys.hasNext()) {
                String key = keys.next();
                String value = headers.optString(key);
                httpHeaders.put(key, value);
            }
            if (!args.has("paths")) {
                throw new IllegalArgumentException("上传路径不能为空");
            }
            JSONArray pathArray = args.optJSONArray("paths");
            if (pathArray.length() < 0) {
                throw new IllegalArgumentException("上传路径不能为空");
            }

            List<File> files = new ArrayList<>();
            for (int i = 0; i < pathArray.length(); i++) {
                File file = new File(pathArray.optString(i));
                if (file.exists()) {
                    files.add(file);
                }
            }

            ThreadUtils.runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    if (null == mLoadingDialog) {
                        mLoadingDialog = new LoadingDialog(ActivityUtils.getTopActivity());
                    }
                }
            });

            OkGo.<String>post(uploadUrl)
                    .headers(httpHeaders)
                    .isMultipart(true)
                    .addFileParams("files", files)
                    .execute(new StringCallback() {

                        @Override
                        public String convertResponse(okhttp3.Response response) throws Throwable {
                            if (!response.isSuccessful()) {
                                throw new OkGoException("服务器异常[code:" + response.code() + "]");
                            }
                            return super.convertResponse(response);
                        }

                        @Override
                        public void onSuccess(Response<String> response) {
                            ThreadUtils.runOnUiThread(new Runnable() {
                                @Override
                                public void run() {
                                    mLoadingDialog.loadSuccess();
                                }
                            });
                            if (null != response.body() && !TextUtils.isEmpty(response.body())) {
                                BridgeResult result = GsonUtils.fromJson(response.body(), BridgeResult.class);
                                handler.complete(success(result.data));
                            } else {
                                handler.complete(fail("data返回为空", response.getException()));
                            }
                        }

                        @Override
                        public void onStart(Request<String, ? extends Request> request) {
                            super.onStart(request);
                            ThreadUtils.runOnUiThread(new Runnable() {
                                @Override
                                public void run() {
                                    mLoadingDialog.setLoadingText("上传中")
                                            .setSuccessText("上传成功")
                                            .setFailedText("上传失败")
                                            .closeFailedAnim()
                                            .closeSuccessAnim()
                                            .show();
                                }
                            });
                        }

                        @Override
                        public void onError(Response<String> response) {
                            super.onError(response);
                            ThreadUtils.runOnUiThread(new Runnable() {
                                @Override
                                public void run() {
                                    mLoadingDialog.loadFailed();
                                }
                            });
                            handler.complete(fail(response.getException().getMessage(), response.getException()));
                        }
                    });
        } catch (Exception e) {
            handler.complete(fail(e.getMessage(), e));
        }
    }

    @JavascriptInterface
    public void delete(Object argsJson, CompletionHandler<String> handler) {
        LogUtils.d("FILE.delete");
        if (null == argsJson) {
            handler.complete(fail("参数不能为空", null));
            return;
        }

        try {
            JSONObject args = (JSONObject) argsJson;
            LogUtils.d("args: " + args.toString());
            if (!args.has("path")) {
                throw new IllegalArgumentException("删除路径不能为空");
            }
            String path = args.getString("path");
            if (TextUtils.isEmpty(path)) {
                throw new IllegalArgumentException("删除路径不能为空");
            }
            // 只删除app目录下的文件或文件夹，其他的不删除
            //String realPath = AppConstants.DOWNLOAD_HTML_FOLDER + "app" + File.separator + (path.startsWith("/") ? path.substring(1) : path);
            // [tylr-update-20221201] 支持删除html下的所有文件
            String realPath = AppConstants.DOWNLOAD_HTML_FOLDER + (path.startsWith("/") ? path.substring(1) : path);
            if(path.equals("*")){
                realPath = AppConstants.DOWNLOAD_HTML_FOLDER;
            }

            boolean result = FileUtils.delete(realPath);
            if (result) {
                handler.complete(success("delete success"));
            } else {
                handler.complete(fail("delete fail", null));
            }
        } catch (Exception e) {
            handler.complete(fail(e.getMessage(), e));
        }
    }

    @JavascriptInterface
    public void unzip(Object argsJson, CompletionHandler<String> handler) {
        LogUtils.d("FILE.unzip");
        if (null == argsJson) {
            handler.complete(fail("参数不能为空", null));
            return;
        }

        try {
            JSONObject args = (JSONObject) argsJson;
            LogUtils.d("args: " + args.toString());
            if (!args.has("source")) {
                throw new IllegalArgumentException("解压源路径不能为空");
            }
            String source = args.getString("source");
            if (TextUtils.isEmpty(source)) {
                throw new IllegalArgumentException("解压源路径不能为空");
            }

            if (!args.has("target")) {
                throw new IllegalArgumentException("解压目标路径不能为空");
            }
            String target = args.getString("target");
            if (TextUtils.isEmpty(target)) {
                throw new IllegalArgumentException("解压目标路径不能为空");
            }
            File sourceFile = new File(source);
            if (!sourceFile.exists()) {
                handler.complete(fail("源文件不存在", null));
                return;
            }
            // 解压到app文件夹
            File destFile = new File(AppConstants.DOWNLOAD_HTML_FOLDER + "app" + File.separator + target);
            // 开始解压
            unZipFiles(sourceFile, destFile, handler);
        } catch (Exception e) {
            handler.complete(fail(e.getMessage(), e));
        }
    }

    @JavascriptInterface
    public void readAsText(Object argsJson, CompletionHandler<String> handler) {
        LogUtils.d("FILE.readAsText");
        if (null == argsJson) {
            handler.complete(fail("参数不能为空", null));
            return;
        }

        try {
            JSONObject args = (JSONObject) argsJson;
            LogUtils.d("args: " + args.toString());
            if (!args.has("path")) {
                throw new IllegalArgumentException("读取文件的路径不能为空");
            }
            String path = args.getString("path");
            if (TextUtils.isEmpty(path)) {
                throw new IllegalArgumentException("读取文件的路径不能为空");
            }

            String result = FileIOUtils.readFile2String(path);
            handler.complete(success(result));

        } catch (Exception e) {
            handler.complete(fail(e.getMessage(), e));
        }
    }

    @JavascriptInterface
    public void readFileByLine(Object argsJson, CompletionHandler<String> handler) {
        LogUtils.d("FILE.readFileByLine");
        if (null == argsJson) {
            handler.complete(fail("参数不能为空", null));
            return;
        }

        try {
            JSONObject args = (JSONObject) argsJson;
            LogUtils.d("args: " + args.toString());
            if (!args.has("path")) {
                throw new IllegalArgumentException("读取文件的路径不能为空");
            }
            String path = args.getString("path");
            if (TextUtils.isEmpty(path)) {
                throw new IllegalArgumentException("读取文件的路径不能为空");
            }

            List<String> result = FileIOUtils.readFile2List(path);
            handler.complete(success(result));

        } catch (Exception e) {
            handler.complete(fail(e.getMessage(), e));
        }
    }

    @JavascriptInterface
    public void download(Object argsJson, CompletionHandler<String> handler) {
        LogUtils.d("FILE.download");
        if (null == argsJson) {
            handler.complete(fail("参数不能为空", null));
            return;
        }

        try {
            JSONObject args = (JSONObject) argsJson;
            LogUtils.d("args: " + args.toString());
            if (!args.has("path")) {
                throw new IllegalArgumentException("下载路径不能为空");
            }
            String path = args.getString("path");
            if (TextUtils.isEmpty(path)) {
                throw new IllegalArgumentException("下载路径不能为空");
            }

            ThreadUtils.runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    if (null == mLoadingDialog) {
                        mLoadingDialog = new LoadingDialog(ActivityUtils.getTopActivity());
                    }
                }
            });

            Observable.create(new ObservableOnSubscribe<String>() {
                        @Override
                        public void subscribe(ObservableEmitter<String> emitter) throws Exception {
                            try {
                                String fileName = getFileName(path);
                                emitter.onNext(fileName);
                                emitter.onComplete();
                            } catch (Exception e) {
                                emitter.onError(e);
                            }
                        }
                    })
                    .subscribeOn(Schedulers.io())
                    .doOnNext(new Consumer<String>() {
                        @Override
                        public void accept(String fileName) throws Exception {
                            OkDownload.getInstance().setFolder(AppConstants.DOWNLOAD_FILE_FOLDER);

                            String fileNameMd5 = EncryptUtils.encryptMD5ToString(fileName);
                            GetRequest<File> request = OkGo.<File>get(path).cacheMode(CacheMode.NO_CACHE);
                            request.headers("Connection", "close");
                            OkDownload.request(AppConstants.DOWNLOAD_FILE_TAG + fileNameMd5, request)
                                    .fileName(fileName)
                                    .save()
                                    .register(new DownloadListener(AppConstants.DOWNLOAD_FILE_TAG + fileNameMd5) {
                                        @Override
                                        public void onStart(Progress progress) {
                                            ThreadUtils.runOnUiThread(new Runnable() {
                                                @Override
                                                public void run() {
                                                    mLoadingDialog.setLoadingText("下载中")
                                                            .setSuccessText("下载成功")
                                                            .setFailedText("下载失败")
                                                            .closeFailedAnim()
                                                            .closeSuccessAnim()
                                                            .show();
                                                }
                                            });
                                        }

                                        @Override
                                        public void onProgress(Progress progress) {

                                        }

                                        @Override
                                        public void onError(Progress progress) {
                                            ThreadUtils.runOnUiThread(new Runnable() {
                                                @Override
                                                public void run() {
                                                    mLoadingDialog.loadFailed();
                                                }
                                            });
                                            handler.complete(fail("下载失败", progress.exception));
                                        }

                                        @Override
                                        public void onFinish(File file, Progress progress) {
                                            ThreadUtils.runOnUiThread(new Runnable() {
                                                @Override
                                                public void run() {
                                                    mLoadingDialog.loadSuccess();
                                                }
                                            });
                                            handler.complete(success(AppConstants.DOWNLOAD_FILE_FOLDER + fileName));
                                        }

                                        @Override
                                        public void onRemove(Progress progress) {

                                        }
                                    })
                                    .start();
                        }
                    })
                    .doOnError(new Consumer<Throwable>() {
                        @Override
                        public void accept(Throwable throwable) throws Exception {
                            handler.complete(fail(throwable.getMessage(), throwable));
                        }
                    })
                    .subscribe();
        } catch (Exception e) {
            handler.complete(fail(e.getMessage(), e));
        }
    }

    private String getFileName(String url) throws Exception {
        String filename = "";
        boolean isOk = false;
        URL myURL = new URL(url);

        URLConnection conn = myURL.openConnection();
        if (conn == null) {
            return null;
        }
        Map<String, List<String>> hf = conn.getHeaderFields();
        if (hf == null) {
            return null;
        }
        Set<String> key = hf.keySet();

        for (String sKey : key) {
            List<String> values = hf.get(sKey);
            for (String value : values) {
                String result;
                try {
                    result = new String(value.getBytes("ISO-8859-1"), "UTF-8");
                    int location = result.indexOf("filename");
                    if (location >= 0) {
                        result = result.substring(location
                                + "filename".length());
                        filename = result
                                .substring(result.indexOf("=") + 1);
                        isOk = true;
                    }
                } catch (UnsupportedEncodingException e) {
                    e.printStackTrace();
                }// ISO-8859-1 UTF-8 gb2312
            }
            if (isOk) {
                break;
            }
        }

        if ("".equals(filename)) {
            filename = url.substring(url.lastIndexOf("/") + 1);
        }
        return filename;
    }

    private void unZipFiles(File source, File dest, CompletionHandler<String> handler) {
        Observable.create(new ObservableOnSubscribe<String>() {
                    @Override
                    public void subscribe(@NotNull ObservableEmitter<String> emitter) throws Exception {
                        try {
                            ZipUtils.unzipFile(source, dest);
                        } catch (IOException e) {
                            emitter.onError(e);
                        }
                        emitter.onNext("");
                        emitter.onComplete();
                    }
                })
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .doOnSubscribe(new Consumer<Disposable>() {
                    @Override
                    public void accept(Disposable disposable) throws Exception {
                        ThreadUtils.runOnUiThread(new Runnable() {
                            @Override
                            public void run() {
                                mLoadingDialog.setLoadingText("解压中")
                                        .setSuccessText("解压成功")
                                        .setFailedText("解压失败")
                                        .closeFailedAnim()
                                        .closeSuccessAnim()
                                        .show();
                            }
                        });
                    }
                })
                .doOnNext(new Consumer<Object>() {
                    @Override
                    public void accept(Object o) throws Exception {
                        ThreadUtils.runOnUiThread(new Runnable() {
                            @Override
                            public void run() {
                                mLoadingDialog.loadSuccess();
                            }
                        });
                        handler.complete(success("解压成功"));
                    }
                })
                .doOnError(new Consumer<Throwable>() {
                    @Override
                    public void accept(Throwable throwable) throws Exception {
                        ThreadUtils.runOnUiThread(new Runnable() {
                            @Override
                            public void run() {
                                mLoadingDialog.loadFailed();
                            }
                        });
                        handler.complete(fail("解压失败", throwable));
                    }
                })
                .subscribe();
    }
}
